const h = (tag, props, children) => {
  // vnode --->javascript 对象--->{}
  return {
    tag,
    props,
    children
  }
}

// 我们需要拿到  vnode 挂载到真实 DOM 上 也就是我们这里的 <div id="tutu"> </div>
const mount = (vnode,container) => {
  // node  -->element
  // 先创建出了真实的元素,并在vnode上保留 这个真实 DOM
  const el = vnode.el = document.createElement(vnode.tag)
  
  // 处理props
  if (vnode.props) {
    for (const key in vnode.props) {
       const value = vnode.props[key]
       // 这里是对于 props 是为函数的情况进行处理
       if(key.startsWith("on")) {
         el.addEventListener(key.slice(2).toLocaleLowerCase(), value)
       } else {
         el.setAttribute(key, value)
       }
    }
  }
  // 处理 子节点   这里只对于 字符串跟数组类型进行了处理
  if(vnode.children) {
    //   数组情况
    if (typeof vnode.children !== "string") {
     vnode.children.forEach(item => {
       // 因为这里的  [children] 数组里 又是一个个h()函数
       // 所以进行 递归  对 item 里面进行mout处理 此时挂载的是当前 VNode 元素上
       mount(item, el)
      })
    } else {
    //  字符串情况
    el.textContent  = vnode.children
   }
  } 
  // 将 el 挂载到container 上
  container.appendChild(el)
}

// 传递进来两个VNode
const patch = (n1, n2) => {
 // 1: 首先先 判断下两个 VNode 的tag 是否相同, 相同的话就直接暴力移除旧的
 if ( n1.tag !== n2.tag) {
   //  移除 旧 VNode 的父元素  
   const n1ElParent = n1.el.parentElement;
   n1ElParent.removeChild(n1.el);
   //  将 新 VNode 挂在 n1的父元素上
   mount(n2,n1ElParent)
 } else {
   //取出 element 对象 并且在 n2 中进行保存
   const el = n2.el = n1.el 
   // 2:   处理props
   const oldProps = n1.props || {}
   const newProps = n2.props || {}
   //  获取所有的 newProps
   for (const key in newProps) {
     const oldValue = oldProps[key]
     const newValue = newProps[key]
     if ( newValue !== oldValue ) {
       if ( key.startsWith("on") ) {
         el.addEventListener(key.slice(2).toLocaleLowerCase(), newValue)
       } else {
         el.setAttribute(key, newValue)
       }
     }
   }
   // 删除就的props
   for (const key in oldProps) {
     if (key.startsWith("on")) { // 对事件监听的判断
       const value = oldProps[key];
       el.removeEventListener(key.slice(2).toLowerCase(), value)
     }
     if (!(key in newProps)) {
       el.removeAttribute(key);
     }
   }


   //处理children
   const oldChildren = n1.children || []
   const newChildren = n2.children || []
   // 如果新vnode  的children 是字符串 类型  就直接进行赋值
   if( typeof newChildren === "string") {
     //  edge case 边界判断
     if( typeof oldChildren === "string") {
       if ( oldChildren === newChildren ) {
         el.textContent = newChildren
       }
     } else {
       el.innerHTML = newChildren
     }
   } else {
     // 新vnode 是数组  旧vnode是字符串的情况
     if ( typeof oldChildren === "string") {
       el.innerHTML = ""
       newChildren.forEach((item) => {
         mount(item, el)
       })
     } else {
       //  都是数组的情况
       // 对于有相同节点进行patch 操作
       // 这里处理没有 key 的情况下
       // 1 先取出 更短的长度进行遍历 进行diff算法
       const commonLength = Math.min(oldChildren.length, newChildren.length)
       for(let i = 0; i < commonLength.length; i ++) {
         // 将公共 部分 进行 patch()
         patch(oldChildren, newChildren)
       }
       //  新的节点 长度大于 旧的长度  是将多余的部分进行挂载操作  mount()
       if( newChildren.length > oldChildren.length) {
         newChildren.slice(oldChildren.length).forEach(item => {
           mount(item, el)
         })
       }
       //  新的节点 小于旧的节点长度,  将 旧的节点 进行移除操作  removechild()
       if( newChildren.length < oldChildren.length) {
         oldChildren.slice(commonLength.length).forEach(item => {
           el.removeChild(item)
         })
       }
     }
   }

 }
}